package handler

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"gozeroSingle/internal/tools"
	"gozeroSingle/internal/types"
	"gozeroSingle/utils"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strconv"

	"github.com/zeromicro/go-zero/rest/httpx"
)

/*
 +----------------------------------------------------------------------
 + Title        : IndexHandler
 + Author       : huwl
 + Version      : 1.0.0
 + Initial-Time : 2025-08-08
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : 首页处理器
 +----------------------------------------------------------------------
*/

type IndexHandler struct {
	BaseHandler
}

/**
 * 首页
 *
 * @author huwl
 */
func (control *IndexHandler) Index(w http.ResponseWriter, r *http.Request) {
	control.SvcCtx.Logger.Info("xxxx")
	control.BaseSuccess(r, w, control.WithMessage("欢迎使用 gozero v1.5.0 单体框架！！！"))
}

/**
 * 案例
 *
 * @author huwl
 */
func (control *IndexHandler) Demo(w http.ResponseWriter, r *http.Request) {
	control.BaseSuccess(r, w, control.WithMessage("index demo"))
}

/**
 * mongo案例
 *
 * @author huwl
 */
func (control *IndexHandler) MongoDemo(w http.ResponseWriter, r *http.Request) {
	mongoInstance, err := tools.NewMongoInstance(control.SvcCtx)
	if err != nil {
		control.BaseError(r, w, control.WithMessage(err.Error()))
		return
	}

	fmt.Println("mongoInstance =", mongoInstance)

	control.BaseSuccess(r, w, control.WithMessage("mongo demo"))
}

/**
 * 请求参数案例
 *
 * form-data提交数组参数无法解析，只能使用json
 * @author huwl
 */
func (control *IndexHandler) RequestParamsDemo(w http.ResponseWriter, r *http.Request) {
	fmt.Printf("Content-Type: %s\n", r.Header.Get("Content-Type"))
	if err := r.ParseForm(); err == nil {
		fmt.Printf("Form values: %v\n", r.Form["ids"]) // 查看原始表单数据
	}
	var req types.IndexRequest
	if err := httpx.Parse(r, &req); err != nil {
		control.BaseError(r, w, control.WithMessage(err.Error()))
		return
	}

	fmt.Println("req =========== ", req)
}

/**
 * 单文件上传
 *
 * @author huwl
 */
func (control *IndexHandler) SingleFileUpload(w http.ResponseWriter, r *http.Request) {
	// 解析普通表单数据（如果需要）到你的结构体
	var req types.UploadRequest
	if err := httpx.Parse(r, &req); err != nil {
		httpx.Error(w, err)
		return
	}

	// 1. 解析 multipart form
	// 建议设置适当的最大内存值，超过部分会使用临时文件
	err := r.ParseMultipartForm(32 << 20) // 例如 32MB
	if err != nil {
		control.BaseError(r, w, control.WithMessage(err.Error()))
		return
	}

	// 2. 获取单文件
	file, header, err := r.FormFile("file") // "file" 对应结构体标签和表单字段名
	if err != nil {
		control.BaseError(r, w, control.WithMessage(err.Error()))
		return
	}
	defer file.Close()

	// 3. 创建目标文件
	// 生成安全的文件名或使用原始文件名
	dstPath := filepath.Join("uploads", header.Filename)
	dstFile, err := os.Create(dstPath)
	if err != nil {
		control.BaseError(r, w, control.WithMessage(err.Error()))
		return
	}
	defer dstFile.Close()

	// 4. 拷贝文件数据
	_, err = io.Copy(dstFile, file)
	if err != nil {
		control.BaseError(r, w, control.WithMessage(err.Error()))
		return
	}

	// 5. 处理其他普通表单字段（如果需要）
	// desc := r.FormValue("desc")

	// 文件保存成功，进行后续业务处理...
}

/**
 * 批量文件上传
 *
 * @author huwl
 */
func (control *IndexHandler) BatchFileUpload(w http.ResponseWriter, r *http.Request) {
	// 1. 解析 multipart form
	// 设置适当的内存大小限制（例如 32MB）
	err := r.ParseMultipartForm(32 << 20)
	if err != nil {
		control.BaseError(r, w, control.WithMessage(err.Error()))
		return
	}

	// 2. 获取多文件
	form := r.MultipartForm
	files := form.File["files"] // "files" 对应前端表单中的字段名

	var savedFilePaths []string

	// 3. 遍历处理每个文件
	for _, fileHeader := range files {
		// 打开上传的文件
		file, err := fileHeader.Open()
		if err != nil {
			control.BaseError(r, w, control.WithMessage(err.Error()))
			return
		}
		defer file.Close()

		// 4. 创建安全的文件名
		// 使用时间戳和随机数避免文件名冲突
		imageExt := filepath.Ext(fileHeader.Filename)
		var filename = strconv.FormatInt(utils.GetUnixNano(), 10)
		var h = md5.New()
		h.Write([]byte(filename)) // 需要加密的字符串
		filename = hex.EncodeToString(h.Sum(nil)) + imageExt
		savePath := filepath.Join("uploads", filename)

		// 5. 创建目标文件
		dstFile, err := os.Create(savePath)
		if err != nil {
			control.BaseError(r, w, control.WithMessage(err.Error()))
			return
		}

		// 6. 拷贝文件数据
		_, err = io.Copy(dstFile, file)
		dstFile.Close() // 及时关闭文件

		if err != nil {
			control.BaseError(r, w, control.WithMessage(err.Error()))
			return
		}

		savedFilePaths = append(savedFilePaths, savePath)
	}

	fmt.Println("savedFilePaths ==== ", savedFilePaths)
}
